package org.mycub.server.requester;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.mycub.server.JettyServer;
import org.mycub.server.parser.CollectBusStation;
import org.mycub.server.parser.CollectFreeParking;
import org.mycub.server.parser.CollectInternetAccess;
import org.mycub.server.parser.CollectPaidParking;
import org.mycub.server.parser.CollectPublicToilet;
import org.mycub.server.parser.CollectTramStation;
import org.mycub.server.parser.CollectVCUBStation;
import org.mycub.server.requester.descriptors.BusStationsDescription;
import org.mycub.server.requester.descriptors.FreeParkingsDescription;
import org.mycub.server.requester.descriptors.InternetAccessDescription;
import org.mycub.server.requester.descriptors.LayerDescription;
import org.mycub.server.requester.descriptors.PaidParkingsDescription;
import org.mycub.server.requester.descriptors.PublicToiletsDescription;
import org.mycub.server.requester.descriptors.TramStationsDescription;
import org.mycub.server.requester.descriptors.VCUBStationsDescription;

public class CollecterAgent {

	private long minTimeToRefresh;
	private String getCUBCapabilities = "http://data.lacub.fr/wfs" +
			"?key=TO5JWRIOA3" +
			"&service=WFS" +
			"&version=1.0.0" +
			"&request=GetCapabilities";
	
	private List<DataFile> CUBFILES;
	private List<DataFile> OPENDATAFILES;

	public CollecterAgent() {
		try {

			createRepertory();
			setMinTimeToRefresh(collectMinTimeToRefresh());

		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}


	}

	public void createRepertory(){

		Long curTime = JettyServer.getTime();

		// TODO Créer le dossier de collecte du nouveau layer
		
		List<DataFile> tmp = new ArrayList<DataFile>();
		tmp.add(new DataFile(TramStationsDescription.class, CollectTramStation.class, curTime));
		tmp.add(new DataFile(BusStationsDescription.class, CollectBusStation.class, curTime));
		tmp.add(new DataFile(VCUBStationsDescription.class, CollectVCUBStation.class, curTime));

		CUBFILES = Collections.unmodifiableList(tmp);

		tmp = new ArrayList<DataFile>();
		tmp.add(new DataFile(FreeParkingsDescription.class, CollectFreeParking.class, curTime));
		tmp.add(new DataFile(PaidParkingsDescription.class, CollectPaidParking.class, curTime));
		tmp.add(new DataFile(InternetAccessDescription.class, CollectInternetAccess.class, curTime));
		tmp.add(new DataFile(PublicToiletsDescription.class, CollectPublicToilet.class, curTime));

		OPENDATAFILES = Collections.unmodifiableList(tmp);
	}

	public long collectMinTimeToRefresh() throws InstantiationException, IllegalAccessException{
		List<Long> timesToRefresh = new ArrayList<Long>();

		for(DataFile aFile : getCUBFiles()){
			
			Class<?> aCUBClass = aFile.getSource();
			LayerDescription itemLoaded = (LayerDescription) aCUBClass.newInstance();
			timesToRefresh.add(itemLoaded.getTimeToRefresh());
		}

		for(DataFile aFile : getOPENDATAFiles()){
			
			Class<?> anODATAClass = aFile.getSource();
			LayerDescription itemLoaded = (LayerDescription) anODATAClass.newInstance();
			timesToRefresh.add(itemLoaded.getTimeToRefresh());
		}

		Collections.sort(timesToRefresh);
		return timesToRefresh.get(0);


	}

	public List<DataFile> getCUBFiles() {
		return CUBFILES;
	}

	public List<DataFile> getOPENDATAFiles() {
		return OPENDATAFILES;
	}

	public List<DataFile> getFeaturesCollections() throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{

		List<DataFile> listFeatureCol = new ArrayList<DataFile>();
		
		List<DataFile> files = getCUBFiles();
		
		for(DataFile aFile : files){
			
			Class<?> item = aFile.getSource();
			LayerDescription itemLoaded = (LayerDescription) item.newInstance();

			Long date = getCurrentDate();
			Long refreshDate = aFile.getRefreshTime();
			if(date>=refreshDate){

				SimpleFeatureCollection featureCol = getFeaturesFromCUB(itemLoaded.getTypeName(), itemLoaded.getQuery());
				aFile.setResultat(featureCol);
				aFile.setRefreshTime(updatedRefreshmentDate(itemLoaded));
				
				listFeatureCol.add(aFile);
			}

		}		
		return listFeatureCol;
	}

	public List<DataFile> getJSONCollections() throws InstantiationException, IllegalAccessException, IOException{

		List<DataFile> listJSONCol =  new ArrayList<DataFile>();

		List<DataFile> files = getOPENDATAFiles();
		
		for(DataFile aFile : files){
			
			Class<?> item = aFile.getSource();
			LayerDescription itemLoaded = (LayerDescription) item.newInstance();
			
			Long date = getCurrentDate();
			Long refreshDate = aFile.getRefreshTime();
			if(date>=refreshDate){
				
				String jsonCol = getJSONFromOpenData(itemLoaded.getJsonURL());
				aFile.setResultat(jsonCol);
				
				aFile.setRefreshTime(updatedRefreshmentDate(itemLoaded));
				
				listJSONCol.add(aFile);
			}
		}
		return listJSONCol;
	}

	public SimpleFeatureCollection getFeaturesFromCUB(String typeName, Query query) throws IOException  {

		Map<Object, Object> connectionParameters = new HashMap<Object,Object>();
		connectionParameters.put("WFSDataStoreFactory:GET_CAPABILITIES_URL", getCUBCapabilities);

		// Connection
		DataStore data = DataStoreFinder.getDataStore( connectionParameters );
		SimpleFeatureSource source = data.getFeatureSource(typeName);

		SimpleFeatureCollection featureCol = null;
		if(query != null){ featureCol = source.getFeatures( query );}
		else { featureCol = source.getFeatures();}

		return featureCol;
	}

	public String getJSONFromOpenData(URL url) throws IOException{

		return readRequestResult(url);
	}

	public String readRequestResult(URL targetURL) throws IOException{

		HttpURLConnection connection = null;
		try {
			//Create connection
			connection = (HttpURLConnection)targetURL.openConnection();
			connection.setRequestMethod("GET");
			connection.setUseCaches (false);
			connection.setDoInput(true);
			connection.setDoOutput(true);

			//Get Response	
			InputStream is = connection.getInputStream();
			BufferedReader rd = new BufferedReader(new InputStreamReader(is));
			String line;
			StringBuffer response = new StringBuffer(); 
			while((line = rd.readLine()) != null) {
				response.append(line);
				response.append('\r');
			}
			rd.close();
			return response.toString();

		} catch (Exception e) {

			e.printStackTrace();
			return null;

		} finally {

			if(connection != null) {
				connection.disconnect(); 
			}
		}

	}

	public long getMinTimeToRefresh() {
		return minTimeToRefresh;
	}

	public void setMinTimeToRefresh(long minTimeToRefresh) {
		this.minTimeToRefresh = minTimeToRefresh;
	}

	public Long getCurrentDate(){
		return JettyServer.getTime();
	}

	public Long updatedRefreshmentDate(LayerDescription itemLoaded){
		long curTime = JettyServer.getTime();
		long timeToRef = itemLoaded.getTimeToRefresh();
		
		return curTime + timeToRef;
	}
}


